// // 加载gltf库
// import {registerGLTFLoader} from '../../utils/gltf-loader.js';
// // 相机每帧图像作为threejs场景的背景图
// import webglBusiness from './webglBusiness.js'
// noinspection JSIgnoredPromiseFromCall,JSUnusedGlobalSymbols,JSUnusedLocalSymbols,TypeScriptValidateJSTypes

import './WebglBusiness'
import {WebglBusiness} from "db://assets/scripts/ArUtil/WebglBusiness";

export class CameraBusiness {
    // 近截面
    static NEAR = 0.001
    // 远截面
    static FAR = 1000
    // 相机、场景、渲染器
    static camera;
    static scene;
    static renderer;

    // 画布对象
    static canvas;
    // var touchX, touchY;
    // threejs对象
    static THREE;
    // 自定义的3D模型
    static mainModel;
    // AR会话
    static session;
    // 光标模型、跟踪时间的对象
    static reticle
    static clock;
    // 保存3D模型的动画
    static mixers: any[];
    // 设备像素比例
    static devicePixelRatio;
    // 模型的默认缩放大小
    static modelScale = 0.01;
    // 字体地址
    static fontUrl = 'https://m.sanyue.red/demo/fonts/helvetiker_regular.typeface.json'
    // 字体
    static fontFace;

    static initWorldTrack(model) {
        model.position.set(0, -1, -0.8)
        CameraBusiness.scene.add(model)
    }

    static setTextPosition(model1, model2) {
        // 右侧文字
        model1.position.set(0.1, 0.16, -0.7)
        CameraBusiness.scene.add(model1)

        // 左侧文字
        model2.position.set(-0.1, 0, -0.7)
        CameraBusiness.scene.add(model2)
    }

    // 加载3D模型
    static loadModel(modelUrl, callback) {

        let loader = new CameraBusiness.THREE.GLTFLoader();
        wx.showLoading({
            title: 'Loading Model...',
        });
        loader.load(modelUrl,
            function (gltf) {
                console.log('loadModel', 'success');
                wx.hideLoading();
                let model = gltf.scene;
                model.scale.set(CameraBusiness.modelScale, CameraBusiness.modelScale, CameraBusiness.modelScale)
                CameraBusiness.mainModel = model;
                let animations = gltf.animations;

                if (callback) {
                    callback(model, animations);
                }
            },
            null,
            function (error) {
                console.log('loadModel', error);
                wx.hideLoading();
                wx.showToast({
                    title: 'Loading model failed.',
                    icon: 'none',
                    duration: 3000,
                });
            });
    }

    // 更新3D模型地址
    static updateModel(modelUrl) {
        let loader = new CameraBusiness.THREE.GLTFLoader();
        // loading
        wx.showLoading({
            title: 'Loading Model...',
        });
        loader.load(modelUrl,
            function (gltf) {
                console.log('loadModel', 'success');
                let model = gltf.scene;
                // 复制已有模型的变换
                CameraBusiness.addModelByReticle(model, CameraBusiness.mainModel, true)
                // remove old model
                CameraBusiness.scene.remove(CameraBusiness.mainModel);
                // save new model
                CameraBusiness.mainModel = model;

                wx.hideLoading();
            },
            null,
            function (error) {
                console.log('loadModel', error);
                wx.hideLoading();
                wx.showToast({
                    title: 'Loading model failed.',
                    icon: 'none',
                    duration: 3000,
                });
            });

        wx.hideLoading();
    }

    // 加载3D模型的动画
    static createAnimation(model, animations, clipName) {
        if (!model || !animations) {
            return
        }

        // 动画混合器
        const mixer = new CameraBusiness.THREE.AnimationMixer(model)
        for (let i = 0; i < animations.length; i++) {
            const clip = animations[i]
            if (clip.name === clipName) {
                const action = mixer.clipAction(clip)
                action.play()
            }
        }

        CameraBusiness.mixers.push(mixer)
    }

    // 更新3D模型的动画
    static updateAnimation() {
        const dt = CameraBusiness.clock.getDelta()
        if (CameraBusiness.mixers) {
            CameraBusiness.mixers.forEach(function (mixer) {
                mixer.update(dt)
            })
        }
    }


    // 在threejs的每帧渲染中，使用AR相机更新threejs相机的变换。
    static render(frame) {
        // 更新threejs场景的背景
        WebglBusiness.renderGL(frame)
        // 更新3D模型的动画
        CameraBusiness.updateAnimation()
        // 从ar每帧图像获取ar相机对象
        const ar_camera = frame.camera

        if (ar_camera) {
            // 更新three.js相机对象的视图矩阵
            CameraBusiness.camera.matrixAutoUpdate = false
            CameraBusiness.camera.matrixWorldInverse.fromArray(ar_camera.viewMatrix)
            CameraBusiness.camera.matrixWorld.getInverse(CameraBusiness.camera.matrixWorldInverse)

            // 更新three.js相机对象的投影矩阵
            const projectionMatrix = ar_camera.getProjectionMatrix(CameraBusiness.NEAR, CameraBusiness.FAR)
            CameraBusiness.camera.projectionMatrix.fromArray(projectionMatrix)
            CameraBusiness.camera.projectionMatrixInverse.getInverse(CameraBusiness.camera.projectionMatrix)
        }

        CameraBusiness.renderer.autoClearColor = false
        // 这个是three.js相机对象
        CameraBusiness.renderer.render(CameraBusiness.scene, CameraBusiness.camera)
        // 保留模型的正面和背面
        CameraBusiness.renderer.state.setCullFace(CameraBusiness.THREE.CullFaceNone)
    }

    // 创建threejs场景
    static initTHREE() {
        //TODO:自己创建个canvas,使用wx.createCanvas
        // THREE = createScopedThreejs(canvas)
        console.log('initTHREE')

        //TODO:使用cocos代码加载模型
        // registerGLTFLoader(THREE)

        // 相机
        CameraBusiness.camera = new CameraBusiness.THREE.Camera()
        // 场景
        CameraBusiness.scene = new CameraBusiness.THREE.Scene()

        // 半球光
        const light1 = new CameraBusiness.THREE.HemisphereLight(0xffffff, 0x444444)
        light1.position.set(0, 0.2, 0)
        CameraBusiness.scene.add(light1)

        // 平行光
        const light2 = new CameraBusiness.THREE.DirectionalLight(0xffffff)
        light2.position.set(0, 0.2, 0.1)
        CameraBusiness.scene.add(light2)

        // 渲染层
        CameraBusiness.renderer = new CameraBusiness.THREE.WebGLRenderer({
            antialias: true,
            alpha: true,
        })

        // gamma色彩空间校正，以适应人眼对亮度的感觉。
        CameraBusiness.renderer.gammaOutput = true
        CameraBusiness.renderer.gammaFactor = 2.2

        // 时间跟踪器用作3D模型动画的更新
        CameraBusiness.clock = new CameraBusiness.THREE.Clock()
    }

    // 调整画布的大小
    static calcCanvasSize() {
        console.log('calcCanvasSize')

        const info = wx.getSystemInfoSync()
        devicePixelRatio = info.pixelRatio
        const width = info.windowWidth
        const height = info.windowHeight
        /* 官方示例的代码
        canvas.width = width * devicePixelRatio / 2
        canvas.height = height * devicePixelRatio / 2
        */
        CameraBusiness.renderer.setPixelRatio(devicePixelRatio);
        CameraBusiness.renderer.setSize(width, height);
    }

    // 启动AR会话
    static initEnvironment(canvasDom) {
        console.log('initEnvironment')
        // 画布组件的对象
        CameraBusiness.canvas = canvasDom
        // 创建threejs场景
        CameraBusiness.initTHREE()
        // 创建AR会话
        CameraBusiness.session = wx.createVKSession({
            track: {
                // mode参数
                // 1表示检测水平平面
                // 2表示检测垂直平面
                // 3表示检测水平和垂直平面
                // 0表示不检测平面
                plane: {mode: 1},
            },
            // 新增version参数
            version: 'v2',
        })
        // 开始AR会话
        CameraBusiness. session.start(err => {
            if (err) {
                console.log('session.start', err)
                return
            }
            console.log('session.start', 'ok')

            // 监视小程序窗口变化
            CameraBusiness.session.on('resize', function () {
                console.log('session on resize')
                CameraBusiness.calcCanvasSize()
            })

            // 设置画布的大小
            CameraBusiness.calcCanvasSize()

            // 初始化webgl的背景
            WebglBusiness.initGL(CameraBusiness.renderer)

            // 每帧渲染
            const onFrame = function (timestamp) {
                if (!CameraBusiness.session) {
                    return
                }
                // 从AR会话获取每帧图像
                const frame = CameraBusiness.session.getVKFrame(CameraBusiness.canvas.width, CameraBusiness.canvas.height)
                if (frame) {
                    // threejs渲染过程
                    CameraBusiness.render(frame)
                }
                CameraBusiness.session.requestAnimationFrame(onFrame)
            }
            CameraBusiness.session.requestAnimationFrame(onFrame)
        })
    }

    // 在光标的位置放置3D模型
    // model:3D模型对象
    // copyModel：被复制的3D模型对象
    // isAddModel:是否将3D模型加入到threejs场景
    static addModelByReticle(model, copyModel, isAddModel) {
        model.matrixAutoUpdate = true
        model.position.copy(copyModel.position)
        model.rotation.copy(copyModel.rotation)
        console.log('addModelByReticle')
        if (isAddModel) {
            CameraBusiness.scene.add(model)
        }
    }

    // 在手指点击的位置放置3D模型
    // resetPanel：是否用现实环境中新的平面作为AR的空间坐标系
    // evt：触摸事件
    // isAddModel:是否将3D模型加入到threejs场景
    static addModelByHitTest(evt, resetPanel, isAddModel) {
        // 点击可移动3D模型位置
        const touches = evt.changedTouches.length ? evt.changedTouches : evt.touches
        if (touches.length === 1) {
            const touch = touches[0]
            const hitTestRes = CameraBusiness.session.hitTest(touch.x * devicePixelRatio / CameraBusiness.canvas.width,
                touch.y * devicePixelRatio / CameraBusiness.canvas.height,
                resetPanel)

            if (hitTestRes && hitTestRes.length) {
                CameraBusiness.mainModel.matrixAutoUpdate = true
                CameraBusiness. mainModel.matrix.fromArray(hitTestRes[0].transform)
                // 将矩阵分解到平移position、旋转quaternion，但不修改缩放scale。
                CameraBusiness. mainModel.matrix.decompose(CameraBusiness.mainModel.position, CameraBusiness.mainModel.quaternion, new CameraBusiness.THREE.Vector3())
                console.log('addModelByHitTest', CameraBusiness.mainModel.position)

                if (isAddModel) {
                    CameraBusiness.scene.add(CameraBusiness.mainModel)
                }
            } else {
                // 如果wx.createVKSession()没有设置检测平面（mode=1)，则session.hitTest()会一直失败。
                console.log('addModelByHitTest', 'no result')
            }
        }
    }

    static createText(message, colorIndex) {
        if (!CameraBusiness.fontFace) {
            return
        }
        // 颜色范围
        const colorArray = [0xff6699, 0x00ff99, 0x0066ff, 0x006600, 0xff0099]
        const matLite = new CameraBusiness.THREE.MeshBasicMaterial({
            color: colorArray[colorIndex],
            side: CameraBusiness.THREE.DoubleSide,
        });
        const shapes =CameraBusiness. fontFace.generateShapes(message, 100);
        const geometry = new CameraBusiness.THREE.ShapeGeometry(shapes);
        geometry.computeBoundingBox();
        const xMid = -0.5 * (geometry.boundingBox.max.x - geometry.boundingBox.min.x);
        geometry.translate(xMid, 0, 0);
        const model = new CameraBusiness.THREE.Mesh(geometry, matLite);
        // 字体缩放
        const fontScale = 0.0005
        model.scale.set(fontScale, fontScale, fontScale)

        return model;
    }

    // 加载文字模型（只支持英文字母）
    static loadTextModel(callback) {
        const loader = new CameraBusiness.THREE.FontLoader();
        loader.load(CameraBusiness.fontUrl, function (font) {
                console.log('loadTextModel', 'success')
                CameraBusiness.fontFace = font

                if (callback) {
                    callback()
                }
            },
            null,
            function (error) {
                console.log('loadTextModel', error);
            });
    }


    // 将对象回收
    static dispose() {
        if (CameraBusiness.renderer) {
            CameraBusiness. renderer.dispose()
            CameraBusiness.renderer = null
        }
        if (CameraBusiness.scene) {
            CameraBusiness.scene.dispose()
            CameraBusiness.scene = null
        }
        if (CameraBusiness.camera) {
            CameraBusiness.camera = null
        }
        if (CameraBusiness.mainModel) {
            CameraBusiness. mainModel = null
        }

        if (CameraBusiness.mixers) {
            CameraBusiness. mixers.forEach(function (mixer) {
                mixer.uncacheRoot(mixer.getRoot())
            })
            CameraBusiness. mixers = []
        }
        if (CameraBusiness.clock) {
            CameraBusiness.clock = null
        }
        if (CameraBusiness.THREE) {
            CameraBusiness.THREE = null
        }

        if (CameraBusiness.canvas) {
            CameraBusiness.canvas = null
        }
        if (CameraBusiness.session) {
            CameraBusiness.session = null
        }

        if (CameraBusiness.reticle) {
            CameraBusiness.reticle = null
        }

        if (devicePixelRatio) {
            devicePixelRatio = null
        }

        WebglBusiness.dispose()
    }
}


